package com.cskaoyan.wordmemorize.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.model.VoidResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cskaoyan.wordmemorize.auth.StpKit;
import com.cskaoyan.wordmemorize.common.constant.ResultCodeEnum;
import com.cskaoyan.wordmemorize.common.exception.BusinessException;
import com.cskaoyan.wordmemorize.common.upload.AliOssProperties;
import com.cskaoyan.wordmemorize.converter.EmployeeConverter;
import com.cskaoyan.wordmemorize.dao.entity.EmployeeDO;
import com.cskaoyan.wordmemorize.dao.entity.EmployeeRoleDO;
import com.cskaoyan.wordmemorize.dao.entity.RoleDO;
import com.cskaoyan.wordmemorize.dao.mapper.EmployeeMapper;
import com.cskaoyan.wordmemorize.dao.mapper.EmployeeRoleMapper;
import com.cskaoyan.wordmemorize.dao.mapper.RoleMapper;
import com.cskaoyan.wordmemorize.dto.admin.DeleteEmployeeRoleOperateDTO;
import com.cskaoyan.wordmemorize.dto.admin.EmployeeDTO;
import com.cskaoyan.wordmemorize.dto.admin.PageDTO;
import com.cskaoyan.wordmemorize.request.EmployeeCommand;
import com.cskaoyan.wordmemorize.request.EmployeePageRequest;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.service.EmployeeService;
import org.apache.ibatis.executor.BatchResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, EmployeeDO> implements EmployeeService {


    @Autowired
    EmployeeConverter employeeConverter;
    @Autowired
    OSS ossClient;
    @Autowired
    AliOssProperties aliOssProperties;
    @Autowired
    EmployeeMapper employeeMapper;
    @Autowired
    EmployeeRoleMapper employeeRoleMapper;
    @Autowired
    RoleMapper roleMapper;


    // 上传头像
    @Override
    public EmployeeDTO uploadAvatar(MultipartFile file) {
        // 构建文件名字填写 构建oss文件完整路径，路径中不能包含Bucket名称
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null) {
            throw new RuntimeException("文件名不能为空");
        }
        String ossFileName = "update/avatar" + UUID.randomUUID() + originalFilename;
        // 获取流并通过流上传文件
        PutObjectResult putObjectResult;
        try {
            InputStream inputStream = file.getInputStream();
            putObjectResult = ossClient.putObject(aliOssProperties.getBucketName(), ossFileName, inputStream);
        } catch (OSSException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        System.out.println("putObjectResult = " + putObjectResult);
        String imageUrl = "https://" +
                aliOssProperties.getBucketName() +
                "." +
                aliOssProperties.getEndpoint() +
                ossFileName;
//        SaSession session = StpUtil.getSession();
//        long id = (long) session.get("employeeId");
//        long id = 1859792809160802305l;
//         long id = StpKit.ADMIN.getLoginIdAsLong();;
        // 将图片添加到对应的employee表中，并返回对象
        EmployeeDO employeeDO = new EmployeeDO();
        employeeDO.setAvatar(imageUrl);
        // employeeDO.setId(id);
        // 如果原来有图片则需要删除原来的图片
        // TODO  如果原来有图，要删除Oss中原来的图片
        boolean success = updateById(employeeDO);
//        return success ? employeeConverter.employeeDO2DTO(getById(id)):null;
        EmployeeDTO employeeDTO = employeeConverter.employeeDO2DTO(employeeDO);
        return employeeDTO;
    }

    @Override
    public EmployeeDTO login(String userName, String password) {
        // 1. 查询数据库，验证后台用户的用户名和密码

        // 得到密文密码
        String passwd = SaSecureUtil.md5(password);
        System.out.println(userName);
        LambdaQueryWrapper<EmployeeDO> employeeWrapper = new LambdaQueryWrapper<>();
        employeeWrapper.eq(EmployeeDO::getName, userName)
                .eq(EmployeeDO::getPassword, passwd);

        // 查询满足条件的员工
        EmployeeDO one = getOne(employeeWrapper);
        if (one == null) {
            throw new BusinessException(ResultCodeEnum.LOCAL_LOGIN_FAIL);
        }

        return employeeConverter.employeeDO2DTO(one);
    }

    /*
        根据id获取Employee对象
     */
    @Override
    public EmployeeDTO getEmployeeInfo(Long employeeId) {
        EmployeeDO employeeDO = employeeMapper.queryByIdWithPermissions(employeeId);
        EmployeeDTO employeeDTO = employeeConverter.employeeDO2DTO(employeeDO);
        return employeeDTO;
    }

    @Override
    public PageDTO<EmployeeDTO> getEmployeePage(PageRequest baseRequest) {
        EmployeePageRequest request = (EmployeePageRequest) baseRequest;

        List<EmployeeDO> employeeDOS = employeeMapper.queryEmployeeDOsByKeyword(request.getKeyword(),request.getSort(),request.getOrder());
        Integer count = request.getCount();
        Integer pageNum = request.getPageNum();
        Integer page = request.getPage();

//        int size = employeeDOS.size();
//        employeeDOS.subList(0,(pageNum-1)*count).clear();
        List<EmployeeDO> list = employeeDOS
                .stream()
                .skip((pageNum - 1) * count)
                .limit(count)
                .toList();
        PageDTO<EmployeeDTO> employeeDTOPageDTO = employeeConverter.emoloyeePage2PageDTO(list,
                (long) (list.size()));
        return employeeDTOPageDTO;
    }

    @Override
    public void addEmployee(EmployeeCommand command) {
        EmployeeDO employeeDO = employeeConverter.command2EmployeeDO(command);
        employeeDO.setPassword(SaSecureUtil.md5(command.getPassword()));
        saveOrUpdate(employeeDO);
        long employeeId = employeeDO.getId();
        List<Long> roleIds = employeeDO.getRoleIds();
        //根据roleIds构造 list<role_employee> 添加到数据库
        List<EmployeeRoleDO> employeeRoleDOList = roleIds.stream()
                .map(roleId -> {
                    EmployeeRoleDO employeeRoleDO = new EmployeeRoleDO();
                    employeeRoleDO.setRoleId(roleId);
                    employeeRoleDO.setEmployeeId(employeeId);
                    return employeeRoleDO;
                })
                .toList();
        employeeRoleMapper.insert(employeeRoleDOList);
    }

    @Override
    public void updateEmployee(EmployeeCommand command) {
        EmployeeDO employeeDO = employeeConverter.command2EmployeeDO(command);
        // 在employee表中更新角色
        updateById(employeeDO);
        // 更新employee_role的表中添加数据
        // 0. 确定新的rolIds -> newRoleIds
        List<Long> newRoleIds = command.getRoleIds().stream().map(roleId->Long.valueOf(roleId)).collect(Collectors.toList());
        // 1. 获取旧的roleIds ->oldRoleIds
        List<Long> oldRoleIds = employeeRoleMapper.selectList(
                new LambdaQueryWrapper<EmployeeRoleDO>()
                .eq(EmployeeRoleDO::getEmployeeId, command.getId()))
                .stream()
                .map(employeeRoleDO -> employeeRoleDO.getRoleId())
                .collect(Collectors.toList());;
        // 2. 确定要删除的roleIds -> deleteRoleIds
        List<Long> copyOldRoleIds = new ArrayList<>();
        copyOldRoleIds.addAll(oldRoleIds);
        oldRoleIds.removeAll(newRoleIds);
        List<Long> deleteRoleIds = oldRoleIds;
        // 3. 确定需要插入的roleIds -> insertRoleIds
        newRoleIds.removeAll(copyOldRoleIds);
        List<Long> insertRoleIds = newRoleIds;

        // 删除操作
        if(!deleteRoleIds.isEmpty()){
            int delete = employeeRoleMapper.delete(new LambdaQueryWrapper<EmployeeRoleDO>()
                    .eq(EmployeeRoleDO::getEmployeeId, employeeDO.getId())
                    .in(EmployeeRoleDO::getRoleId, deleteRoleIds));
        }
        // 添加操作
        //根据insertRoleIds构造 list<role_employee> 添加到数据库
        if(!insertRoleIds.isEmpty()){
            List<EmployeeRoleDO> employeeRoleDOList = insertRoleIds.stream()
                    .map(roleId -> {
                        EmployeeRoleDO employeeRoleDO = new EmployeeRoleDO();
                        employeeRoleDO.setRoleId(roleId);
                        employeeRoleDO.setEmployeeId(employeeDO.getId());
                        return employeeRoleDO;
                    })
                    .toList();
            List<BatchResult> batchResults = employeeRoleMapper.insertOrUpdate(employeeRoleDOList);
            batchResults.forEach(System.out::println);
        }

//        // 在employee_role的表中添加数据
//        long employeeId = employeeDO.getId();
//        List<Long> roleIds = employeeDO.getRoleIds();
//        //根据roleIds构造 list<role_employee> 添加到数据库
//        List<EmployeeRoleDO> employeeRoleDOList = roleIds.stream()
//                .map(roleId -> {
//                    EmployeeRoleDO employeeRoleDO = new EmployeeRoleDO();
//                    employeeRoleDO.setRoleId(roleId);
//                    employeeRoleDO.setEmployeeId(employeeId);
//                    return employeeRoleDO;
//                })
//                .toList();
//        List<BatchResult> batchResults = employeeRoleMapper.insertOrUpdate(employeeRoleDOList);
//
//        // 获取employeeDO在employee_role的表中的role_id与command的roleIDs对比，将不在command中的删除
//        LambdaQueryWrapper<EmployeeRoleDO> eq = new LambdaQueryWrapper<EmployeeRoleDO>()
//                .eq(EmployeeRoleDO::getEmployeeId, employeeId);
//        List<EmployeeRoleDO> employeeRoleDOS = employeeRoleMapper.selectList(eq);
//        List<Long> list = employeeRoleDOS.stream().map(employeeRoleDO -> employeeRoleDO.getRoleId()).collect(Collectors.toList());
//        list.removeAll(roleIds);
//        if(list == null||list.isEmpty()){
//            return;
//        }
//        // 删除employee_role表中与list相关的employee相关的数据
//        LambdaQueryWrapper<EmployeeRoleDO> in = new LambdaQueryWrapper<EmployeeRoleDO>()
//                .eq(EmployeeRoleDO::getEmployeeId, employeeId)
//                .in(EmployeeRoleDO::getRoleId, list);
//        employeeRoleMapper.delete(in);

    }

    @Override
    public void delete(Long employeeId) {
        EmployeeDO employeeDO = getById(employeeId);
        // 获取 图片在桶中的名字用于删除桶中的图片
        if(employeeDO ==null) return;
        String avatarUrl = employeeDO.getAvatar();
        if(avatarUrl !=null){
            String[] split = avatarUrl.split("/");
            String ossFileName = split[split.length - 1];
            VoidResult voidResult = ossClient.deleteObject(aliOssProperties.getBucketName(), ossFileName);
            System.out.println(voidResult);
        }

        // 删除员工
        // 1.employee表
        removeById(employeeId);
        // 2.employee_role表
        LambdaQueryWrapper<EmployeeRoleDO> eq = new LambdaQueryWrapper<EmployeeRoleDO>()
                .eq(EmployeeRoleDO::getEmployeeId, employeeId);
        int delete = employeeRoleMapper.delete(eq);
        System.out.println(delete);
    }

    @Override
    public DeleteEmployeeRoleOperateDTO deleteRole(Long employeeId, Long roleId) {
        LambdaQueryWrapper<EmployeeRoleDO> eq = new LambdaQueryWrapper<EmployeeRoleDO>()
                .eq(EmployeeRoleDO::getEmployeeId, employeeId)
                .eq(EmployeeRoleDO::getRoleId, roleId);
        int delete = employeeRoleMapper.delete(eq);
        System.out.println("==============删除了"+ delete + "条数据==============");
        EmployeeDO employeeDO = getById(employeeId);
        RoleDO roleDO = roleMapper.selectById(roleId);
        DeleteEmployeeRoleOperateDTO deleteEmployeeRoleOperateDTO
                = employeeConverter.toDeleteEmployeeRoleOperateDTO(employeeDO, roleDO);
        return deleteEmployeeRoleOperateDTO;
    }

    @Override
    public void updateLoginInfo(Long employeeId, String ip, LocalDateTime time) {
        EmployeeDO update = new EmployeeDO();
        update.setId(employeeId);
        update.setLastLoginIp(ip);
        update.setLastLoginTime(time);
        // 只更新非null字段
        this.updateById(update);

    }

    @Override
    public Set<String> getPermissionAlias(Long employeeId) {
        Set<String> permissionAlias = employeeMapper.getPermissionAlias(employeeId);
        return permissionAlias;
//        return null;
    }
}
